﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CarbonExchange.AmeeQuery;
using CarbonExchange.Dal;

namespace CarbonExchange.Bll
{
    public class SiteQuestionFactory : FactorySequenceBase<SiteQuestion>
    {
        public SiteQuestionFactory() : base() { }
        public SiteQuestionFactory(IAmeeCommand command) : base(command) { }
        public SiteQuestionFactory(Context context) : base(context) { }
        public SiteQuestionFactory(IAmeeCommand command, Context context) : base(command, context) { }

        protected override void SetDalSequence(SiteQuestion item, int sequence)
        {
            var tmp = DalContext.SiteQuestions.Where(x => x.Id == item.Id && !x.Deleted && x.Sequence != sequence).SingleOrDefault();
            if (tmp != null)
            {
                tmp.Sequence = sequence;
            }
        }

        protected override void MarkItemForDeletion(SiteQuestion item)
        {
            var dataItem = item.Convert(DalContext);
            if(dataItem != null)
            {
                dataItem.Deleted = true;
            }
        }

        protected override void Validate(IQueryable<SiteQuestion> items, CarbonExchange.Bll.Exceptions.ValidationException exp)
        {
            items.Validate(exp, DalContext);
        }

        protected override void PopulateDataChanges(SiteQuestion item, object dataItem)
        {
            var tmp = dataItem as Dal.SiteQuestion;
            if (item.Id == 0)
            {
                item.Id = tmp.Id;
                item.Created = tmp.Created.ToLocalTime();
                item.QuestionName = tmp.Question.QuestionName;
                item.QuestionType = (QuestionTextConfiguration.QuestionTypes)tmp.Question.Type;
                item.SectionId = tmp.Question.SectionId;
                item.SectionName = tmp.Question.Section.Name;
                item.Sequence = tmp.Sequence;
            }
        }

        protected override object GetDataItemForUpdate(SiteQuestion item)
        {
            return item.Convert(DalContext);
        }

        protected override void SetInitalSequence(IQueryable<SiteQuestion> items)
        {
            var tmpItems = items.Where(x => x.Id == 0);
            if(tmpItems.Count() > 1)
            {
                QuestionFactory factory = new QuestionFactory(DalContext);
                var questions = factory.GetAll();
                var joined = tmpItems.Join(questions, x=> x.QuestionId, y => y.Id, (x,y) => new {SiteQuestion = x, Question = y});
                var grouped = joined.GroupBy(x => x.Question.SectionId);
                foreach (var group in grouped)
                {
                    var i = 0;
                    foreach(var tmp in group)
                    {
                        tmp.SiteQuestion.Sequence = i;
                        i++;
                    }
                }
            }
        }

        internal class JoinHelper
        {
            public Dal.SiteQuestion SiteQuestion { get; set; }
            public Dal.Question Question { get; set; }
            public Dal.Section Section { get; set; }
        }

        private IQueryable<JoinHelper> GetSelection()
        {
            return DalContext.SiteQuestions.Where(x => !x.Deleted).OrderBy(x => x.Question.Section.Sequence).ThenBy(x => x.Sequence).Select(x => new JoinHelper() { SiteQuestion = x, Question = x.Question, Section = x.Question.Section });
        }

        public SiteQuestion GetById(int id)
        {
            return GetSelection().Where(x => x.SiteQuestion.Id == id).SingleOrDefault().Convert();
        }

        public IQueryable<SiteQuestion> GetAllBySiteId(int siteId)
        {
            return GetSelection().Where(x => x.SiteQuestion.SiteId == siteId).Convert();
        }

        public IQueryable<SiteQuestion> GetAllBySectionId(int sectionId, int siteId)
        {
            return GetSelection().Where(x => x.Section.Id == sectionId).Where(x => x.SiteQuestion.SiteId == siteId).Convert();
        }
    }

    public static class SiteQuestionConverter
    {

        internal static IQueryable<SiteQuestion> Convert(this IQueryable<SiteQuestionFactory.JoinHelper> source)
        {
            return source.Select(x => ConvertItem(x));
        }

        internal static SiteQuestion Convert(this SiteQuestionFactory.JoinHelper source)
        {
            return ConvertItem(source);
        }

        private static SiteQuestion ConvertItem(SiteQuestionFactory.JoinHelper item)
        {
            if (item != null)
            {
                return new SiteQuestion()
                {
                    Id = item.SiteQuestion.Id,
                    QuestionId = item.Question.Id,
                    QuestionName = item.Question.QuestionName,
                    QuestionType = (QuestionTextConfiguration.QuestionTypes)item.Question.Type,
                    Sequence = item.SiteQuestion.Sequence,
                    SiteId = item.SiteQuestion.SiteId,
                    Created = DateTime.SpecifyKind(item.SiteQuestion.Created, DateTimeKind.Utc).ToLocalTime(),
                    SectionId = item.Section.Id,
                    SectionName = item.Section.Name

                };
            }
            else
            {
                return null;
            }
        }

        internal static IQueryable<Dal.SiteQuestion> Convert(this IQueryable<SiteQuestion> source, Dal.Context context)
        {
            return source.Select(x => ConvertItem(x, context));
        }

        internal static Dal.SiteQuestion Convert(this SiteQuestion source, Dal.Context context)
        {
            return ConvertItem(source, context);
        }

        private static Dal.SiteQuestion ConvertItem(SiteQuestion item, Dal.Context context)
        {
            if (item != null)
            {
                Dal.SiteQuestion tmp = null;
                if (item.Id != 0)
                {
                    tmp = context.SiteQuestions.Where(x => x.Id == item.Id && !x.Deleted).Single();
                }
                else
                {
                    tmp = new CarbonExchange.Dal.SiteQuestion();
                    context.SiteQuestions.InsertOnSubmit(tmp);

                    tmp.SiteId = item.SiteId;
                    tmp.QuestionId = item.QuestionId;
                    tmp.Created = DateTime.UtcNow;

                    item.SectionId = context.Questions.Where(x => x.Id == item.QuestionId).Select(x => x.SectionId).Single();

                    //set the sequence
                    int? max = context.SiteQuestions.Where(x=>x.SiteId == item.SiteId && x.Question.SectionId == item.SectionId).Select(x => (int?)x.Sequence).Max();
                    int seq = max.HasValue ? max.Value + 1 : 0;
                    item.Sequence = item.Sequence + seq;
                }
                tmp.Sequence = item.Sequence;
                return tmp;
            }
            else
            {
                return null;
            }
        }

        internal static void Validate(this IQueryable<SiteQuestion> source, Bll.Exceptions.ValidationException e, Dal.Context context)
        {
            foreach (var item in source)
            {
                Validate(item, e, context);
            }
        }

        internal static void Validate(this SiteQuestion item, Bll.Exceptions.ValidationException e, Dal.Context context)
        {
        }
    }
}
